using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Risiko.State;
using Risiko.Menu;
using Microsoft.Xna.Framework.Input.Touch;


namespace Risiko.Rendering
{

  public enum PlayerColors
  {
    Yellow,
    Red,
    Green,
    Blue,
    Violet,
    Black
  }

  public enum RendererStates
  {
    Main,
    Intro,
    TerritoryAssignment
  }

  public interface IInputEvents
  {
    TouchedTerritory TouchedTerritory { get; }
    TouchedCard TouchedCard { get; }
    bool TouchedNextBtn { get; }
    bool TouchedMenuBtn { get; }
    bool TouchedConfirmBtn { get; }
    bool TouchedDeclineBtn { get; }
    //bool Shake  { get; }
  }

  public struct TouchedTerritory
  {
    public bool IsNull;
    public TerritoryReference territoryRef;
    public GestureType gesture;
  }

  public struct TouchedCard
  {
    public bool IsNull;
    public TerritoryReference territoryRef;
  }

  /// <summary>
  /// This is a game component that implements IUpdateable.
  /// </summary>
  public abstract class BaseRenderer : Microsoft.Xna.Framework.DrawableGameComponent, IInputEvents
  {
    // Interface properties
    public TouchedTerritory TouchedTerritory { get; set; }
    public TouchedCard TouchedCard { get; set; }
    public bool TouchedNextBtn { get; set; }
    public bool TouchedMenuBtn { get; set; }
    public bool TouchedConfirmBtn { get; set; }
    public bool TouchedDeclineBtn { get; set; }
    //public bool Shake  { get; set; }

    // Internal properties
    protected SpriteBatch spriteBatch;
    protected RendererStates rendererState;
    protected State.State gameState;
    protected Texture2D whitePx;
    protected SpriteFont font;
    protected Rectangle gameBounds;

    public BaseRenderer(Game game)
      : base(game)
    {
      spriteBatch = this.Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
      gameState = game.Services.GetService(typeof(State.State)) as State.State;
    }

    /// <summary>
    /// Allows the game component to perform any initialization it needs to before starting
    /// to run.  This is where it can query for any required services and load content.
    /// </summary>
    public override void Initialize()
    {
      Game.Services.AddService(typeof(IInputEvents), this);

      // InputEvents
      TouchedTerritory = new TouchedTerritory() { IsNull = true };
      TouchedCard = new TouchedCard() { IsNull = true };
      TouchedMenuBtn = false;
      TouchedNextBtn = false;

      // Internal objects
      cachedGestures = new List<GestureSample>(10);

      base.Initialize();
    }

    protected override void Dispose(bool disposing)
    {
      Game.Services.RemoveService(typeof(IInputEvents));
      base.Dispose(disposing);
    }


    protected override void LoadContent()
    {
      whitePx = Game.Content.Load<Texture2D>("white_pixel");
      font = Game.Content.Load<SpriteFont>("small_font");

      base.LoadContent();
    }

    public abstract void UpdatePlaceReinforcements(GameTime gameTime);
    public abstract void UpdateAttack(GameTime gameTime);
    public abstract void UpdateConquerMove(GameTime gameTime);
    public abstract void UpdateStrategicMove(GameTime gameTime);
    public abstract void UpdateIntro(GameTime gameTime);
    public abstract void UpdateTerritoryAssignment(GameTime gameTime);
    public abstract void UpdateUI(GameTime gameTime);
    public abstract void UpdateCardsConfirmation(GameTime gameTime);


    protected List<GestureSample> cachedGestures;
    /// <summary>
    /// Allows the game component to update itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    public override void Update(GameTime gameTime)
    {
      // Invalidate input
      TouchedTerritory = new TouchedTerritory() { IsNull = true };
      TouchedCard = new TouchedCard() { IsNull = true };
      TouchedMenuBtn = false;
      TouchedNextBtn = false;
      TouchedConfirmBtn = false;
      TouchedDeclineBtn = false;

      cachedGestures.Clear();

      if (gameState.playerStates[(int)gameState.currentPlayer].isHuman)
      {
        while (TouchPanel.IsGestureAvailable)
          cachedGestures.Add(TouchPanel.ReadGesture());
      }

      switch (rendererState)
      {
        case RendererStates.Main:
          // Main game
          UpdateUI(gameTime);
          switch (gameState.gamePhase)
          {
            case GamePhase.Reinforcements:
              // Turn phase 1: reinforcements assignment
              break;
            case GamePhase.PlayCards:
              // Turn phase 2: Play Cards
              UpdateCardsConfirmation(gameTime);
              break;
            case GamePhase.ArmiesPlacement:
              // Turn phase 2: reinforcements placement
              UpdatePlaceReinforcements(gameTime);
              break;
            case GamePhase.Attack:
              // Turn phase 3: attacks
              UpdateAttack(gameTime);
              break;
            case GamePhase.ConquerMove:
              UpdateConquerMove(gameTime);
              break;
            case GamePhase.StrategicMove:
              // Turn phase 4: strategic move
              UpdateStrategicMove(gameTime);
              break;
            case GamePhase.CardAssignment:
              // Turn phase 5: pick a card
              break;
            case GamePhase.TurnOver:
              // Turn end
              break;
          }
          break;
        case RendererStates.Intro:
          UpdateIntro(gameTime);
          break;
        case RendererStates.TerritoryAssignment:
          UpdateTerritoryAssignment(gameTime);
          break;
      }

      base.Update(gameTime);
    }


    public abstract void DrawBoard(GameTime gameTime);
    public abstract void DrawPlaceReinforcements(GameTime gameTime);
    public abstract void DrawAttack(GameTime gameTime);
    public abstract void DrawConquerMove(GameTime gameTime);
    public abstract void DrawStrategicMove(GameTime gameTime);
    public abstract void DrawPickCard(GameTime gameTime);
    public abstract void DrawIntro(GameTime gameTime);
    public abstract void DrawTerritoryAssignment(GameTime gameTime);
    public abstract void DrawUI(GameTime gameTime);
    public abstract void DrawCardsConfirmation(GameTime gameTime);

    public override void Draw(GameTime gameTime)
    {
      spriteBatch.Begin();
      switch (rendererState)
      {
        case RendererStates.Main:
          // Main game
          DrawBoard(gameTime);
          DrawUI(gameTime);
          switch (gameState.gamePhase)
          {
            case GamePhase.Reinforcements:
              // Turn phase 1: reinforcements assignment
              break;
            case GamePhase.PlayCards:
              // Turn phase 2: card play
              if (gameState.playerStates[(int)gameState.currentPlayer].isHuman)
                DrawCardsConfirmation(gameTime);
              break;
            case GamePhase.ArmiesPlacement:
              // Turn phase 3: reinforcements placement
              DrawPlaceReinforcements(gameTime);
              break;
            case GamePhase.Attack:
              // Turn phase 4: attacks
              DrawAttack(gameTime);
              break;
            case GamePhase.ConquerMove:
              DrawConquerMove(gameTime);
              break;
            case GamePhase.StrategicMove:
              // Turn phase 5: strategic move
              DrawStrategicMove(gameTime);
              break;
            case GamePhase.CardAssignment:
              // Turn phase 6: pick a card
              DrawPickCard(gameTime);
              break;
            case GamePhase.TurnOver:
              // Turn end
              break;
          }
          break;
        case RendererStates.Intro:
          // Game Intro
          DrawIntro(gameTime);
          break;
        case RendererStates.TerritoryAssignment:
          // Game phase 1: territory assignments
          DrawTerritoryAssignment(gameTime);
          break;
      }
      spriteBatch.End();
      base.Draw(gameTime);
    }

    /// <summary>
    /// A function to draw a string centered in the given position
    /// </summary>
    /// <param name="font">The font to use</param>
    /// <param name="msg">The string to draw</param>
    /// <param name="pos">The centered position of the string</param>
    /// <param name="scale">The scale of the message</param>
    protected void DrawCenteredMsg(SpriteFont font, string msg, Vector2 pos, Color color, Vector2 scale)
    {
      spriteBatch.DrawString(font, msg, pos, color, 0.0f, font.MeasureString(msg) / 2, scale, SpriteEffects.None, 1.0f);
    }


    protected void DrawCard(Rectangle cardRect, bool isSelected)
    {
      Color cardColor;
      //for (int i = 0; i < gameState.playerStates[2].Cards.Count; i++)
      //{
      if (isSelected)
        cardColor = Color.Yellow;
      else
        cardColor = Color.White;

      spriteBatch.Draw(whitePx, cardRect, null, cardColor, 0.0f, new Vector2(0.5f, 0.5f), SpriteEffects.None, 0.0f);
      cardRect.Inflate(-2, -3); cardRect.Offset(-2, -3);
      spriteBatch.Draw(whitePx, cardRect, null, Color.Black, 0.0f, new Vector2(0.5f, 0.5f), SpriteEffects.None, 0.0f);
      cardRect.Inflate(-1, -22); cardRect.Offset(-1, -1);
      spriteBatch.Draw(whitePx, cardRect, null, cardColor, 0.0f, new Vector2(0.5f, 0.5f), SpriteEffects.None, 0.0f);
      //}
    }

  }
}
